package com.tomorrow.payments_hodgepodge.service.impl;

import com.paypal.core.PayPalEnvironment;
import com.paypal.core.PayPalHttpClient;
import com.paypal.http.HttpResponse;
import com.paypal.http.exceptions.HttpException;
import com.paypal.orders.*;
import com.paypal.payments.CapturesRefundRequest;
import com.tomorrow.payments_hodgepodge.service.PayPalService;
import com.tomorrow.payments_hodgepodge.util.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Tomorrow
 * @date 2020/11/02 23:58
 */
@Service
@Slf4j
public class PayPalServiceImpl implements PayPalService {
    @Value("${project.PAYPAL.CLIENT_ID}")
    public String clientId;
    @Value("${project.PAYPAL.SECRET}")
    public String secret;
    @Value("${project.PAYPAL.CURRENCY}")
    public String currency;
    @Value("${project.PAYPAL.NOTIFY_URL_SUCCESS}")
    public String notifyURLSuccess;
    @Value("${project.PAYPAL.NOTIFY_URL_FAIL}")
    public String notifyURLFail;

    @Override
    public CommonResult createOrder(String amount) {
        PayPalHttpClient client;
        // 设置环境沙盒或生产
        if (true) {
            client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
        } else {
            client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
        }

        // 配置请求参数
        OrderRequest orderRequest = new OrderRequest();
        orderRequest.checkoutPaymentIntent("CAPTURE");
        List<PurchaseUnitRequest> purchaseUnits = new ArrayList<>();
        purchaseUnits.add(new PurchaseUnitRequest().amountWithBreakdown(new AmountWithBreakdown().currencyCode(currency).value(amount)));
        orderRequest.purchaseUnits(purchaseUnits);
        orderRequest.applicationContext(new ApplicationContext().returnUrl(notifyURLSuccess).cancelUrl(notifyURLFail));
        OrdersCreateRequest request = new OrdersCreateRequest().requestBody(orderRequest);

        HttpResponse<Order> response;
        try {
            response = client.execute(request);
            Order order = response.result();
            String token = order.id();
            log.debug("payPal 支付操作返回结果: " + order);

            String payHref = null;
            String status = order.status();
            if (status.equals("CREATED")) {
                List<LinkDescription> links = order.links();
                for (LinkDescription linkDescription : links) {
                    if (linkDescription.rel().equals("approve")) {
                        payHref = linkDescription.href();
                    }
                }
            }
            Map<String, String> resultMap = new HashMap<String, String>();
            resultMap.put("token", token);
            resultMap.put("payHref", payHref);

            return CommonResult.success("SUCCESS", resultMap);
        } catch (IOException ioe) {
            if (ioe instanceof HttpException) {
                HttpException he = (HttpException) ioe;
                log.error("payPal 下单异常: " + ioe);
                return CommonResult.failMessage(500, "PayPal支付失败", he.getMessage());
            }
            log.error("payPal 下单异常: " + ioe);
            return CommonResult.fail(500, "NetworkTimeout");
        }
    }

    @Override
    public CommonResult captureOrder(String token) {
        PayPalHttpClient client;
        // 设置环境沙盒或生产
        if (true) {
            client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
        } else {
            client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
        }
        OrdersCaptureRequest request = new OrdersCaptureRequest(token);

        try {
            HttpResponse<Order> response = client.execute(request);
            Order order = response.result();
            String status = order.status();
            if (status.equals("COMPLETED")) {
                return CommonResult.success("SUCCESS");
            }
            return CommonResult.success("SUCCESS");
        } catch (IOException ioe) {
            if (ioe instanceof HttpException) {
                HttpException he = (HttpException) ioe;
                log.error("payPal 捕获订单异常: " + ioe);
                return CommonResult.failMessage(500, "PayPal支付捕获失败", he.getMessage());
            }
            log.error("payPal 捕获订单异常: " + ioe);
            return CommonResult.fail(500, "NetworkTimeout");
        }
    }

    @Override
    public CommonResult queryOrder(String token) {
        PayPalHttpClient client;
        // 设置环境沙盒或生产
        if (true) {
            client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
        } else {
            client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
        }

        OrdersGetRequest request = new OrdersGetRequest(token);

        try {
            HttpResponse<Order> response = client.execute(request);
            Order order = response.result();
            return CommonResult.success("SUCCESS", order.status());
        } catch (IOException ioe) {
            if (ioe instanceof HttpException) {
                HttpException he = (HttpException) ioe;
                log.error("payPal 查询订单异常: " + he.getMessage());
                return CommonResult.failMessage(500, "PayPal支付查询失败", he.getMessage());
            }
            log.error("payPal 查询订单异常: " + ioe);
            return CommonResult.fail(500, "NetworkTimeout");
        }
    }

    @Override
    public CommonResult refundOrder(String token) {
        PayPalHttpClient client;
        // 设置环境沙盒或生产
        if (true) {
            client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
        } else {
            client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
        }

        // 查询支付订单, 拿到退款订单号
        OrdersGetRequest ordersGetRequest = new OrdersGetRequest(token);
        try {
            HttpResponse<Order> orderResponse = client.execute(ordersGetRequest);
            Order order = orderResponse.result();
            String captureId = null;
            for (PurchaseUnit purchaseUnit : order.purchaseUnits()) {
                for (Capture capture : purchaseUnit.payments().captures()) {
                    captureId = capture.id();
                }
            }
            if (captureId == null) {
                return CommonResult.fail(500, "PayPal申请退款失败");
            }
            // 申请退款
            CapturesRefundRequest request = new CapturesRefundRequest(captureId);
            HttpResponse<com.paypal.payments.Refund> response = client.execute(request);
            com.paypal.payments.Refund refund = response.result();
            if ("COMPLETED".equals(refund.status())) {
                return CommonResult.success("SUCCESS", captureId);
            }
            return CommonResult.fail(500, "PayPal申请退款失败");
        } catch (IOException ioe) {
            if (ioe instanceof HttpException) {
                HttpException he = (HttpException) ioe;
                log.error("payPal 申请退款异常: " + he.getMessage());
                return CommonResult.failMessage(500, "PayPal支付查询失败", he.getMessage());
            }
            log.error("payPal申请退款异常: " + ioe);
            return CommonResult.fail(500, "NetworkTimeout");
        }
    }

    @Override
    public CommonResult paypalSuccess(HttpServletRequest request) {
        // 通过 token 查询到订单记录
        String token = request.getParameter("token");
        // 拿到订单记录对订单进行捕获操作
        // 目前测试订单没有保存起来, 就手动填写进来
        return captureOrder(token);
    }

    @Override
    public CommonResult paypalFail(HttpServletRequest request) {
        // 通过 token 查询到订单记录
        String token = request.getParameter("token");
        return CommonResult.fail(500, token);
    }
}
